/*
 * @Author: your name
 * @Date: 2021-06-14 12:23:19
 * @LastEditTime: 2021-10-13 20:54:01
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \telescope1080P\src\second_handle.cpp
 */
#ifndef SECOND_HANDLE_CPP
#define SECOND_HANDLE_CPP
#include "second_handle.h"
#include "xlog.h"
#include "gui_engine.h"
#include "common.h"
template <typename FUNC, typename PAGE, typename KEYEVENT>
SecondHandle<FUNC, PAGE, KEYEVENT>::SecondHandle()
{
    /**
     * @brief 
     * 使用带参数构造函数进行初始化，不要使用默认构造函数
     */
    selectLoop = true;
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::SecondPageReset(SecondPage *value)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    KEYEVENT event;
    /**
     * @brief 
     * 抽象流程：重置设置项按键功能映射表。
     */
    if(value)
    {
        value->ResetKeyCmd(event);
    }
    secondPage.reset(value);
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
SecondPage &SecondHandle<FUNC, PAGE, KEYEVENT>::GetSecondPage()
{
    std::lock_guard<std::mutex> locker(m_mutex);
    return *secondPage.get();
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::SecondPageValid()
{
    if (secondPage.get())
    {
        return true;
    }
    else
    {
        LOG_W("invalid second page\n");
        return false;
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::SwitchSelectedItemHandle(Widget *window, int funcSelected, int lastSelected)
{
    return CommonFunc::GetInstance().SwitchSelectedItem(window, funcSelected, lastSelected);
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::CreateItemHandleV2(unsigned int itemNum, Widget *window, int funcSelected, Widget *view2)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(window, "itemView", true, view.get()))
    {
        if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2))
        {
            char name[16] = {0};
            char params[64] = {0};
            sprintf(name, "item%d", funcSelected);
            GuiEngine::GetInstance().SetName(view2, name);
            sprintf(params, "default(x=0,y=%d,w=1194,h=200)", itemNum * 202);
            LOG_I("params = %s, name = %s\n", params, name);
            GuiEngine::GetInstance().SetSelfLayout(view2, params);
            GuiEngine::GetInstance().SetChildrenLayout(view2, "default(c=0,r=1)");
            return true;
        }
    }
    LOG_E("create view failed\n");
    return false;
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::CreateItemHandleV3(unsigned int itemNum, Widget *window, int funcSelected, Widget *view2)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(window, "itemView", true, view.get()))
    {
        if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2))
        {
            char name[16] = {0};
            sprintf(name, "item%d", funcSelected);
            GuiEngine::GetInstance().SetName(view2, name);
            LOG_I("================name = %s\n", name);
            GuiEngine::GetInstance().SetSelfLayout(view2, "default(w=1769,h=113)");
            GuiEngine::GetInstance().SetChildrenLayout(view2, "default(c=0,r=1)");
            return true;
        }
    }
    LOG_E("create view failed\n");
    return false;
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::DestroyHandle(Widget *window, int itemNum)
{
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(window, "itemView", true, view.get()))
    {
        char name2[16] = {0};
        sprintf(name2, "item%d", itemNum);
        LOG_I("item destroy=%s\n", name2);
        std::unique_ptr<Widget> view6(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().Lookup(view.get(), name2, true, view6.get()))
        {
            GuiEngine::GetInstance().Destroy(view6.get());
        }
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::StartDisplayHandle(Widget *window, int funcSelected, std::function<void(Widget *, int)> createOne, unsigned int maxItem)
{
    char name[16] = {0};
    char params[64] = {0};
    // Widget *window = GetThisPage();
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(window, "itemView", true, view.get()))
    {
        LOG_I("find view, create the item %\n");
        for (unsigned int i = 0; i < 4; i++)
        {
            if (i >= maxItem)
            {
                break;
            }
            std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
            if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2.get()))
            {
                name[0] = 0;
                params[0] = 0;
                sprintf(name, "item%d", funcSelected + i);
                GuiEngine::GetInstance().SetName(view2.get(), name);
                sprintf(params, "default(x=0,y=%d,w=1194,h=200)", i * 202);
                LOG_I("params = %s\n", params);
                GuiEngine::GetInstance().SetSelfLayout(view2.get(), params);
                GuiEngine::GetInstance().SetChildrenLayout(view2.get(), "default(c=0,r=1)");
                if (i == 0)
                {
                    // 选中第一个
                    GuiEngine::GetInstance().UseStyle(view2.get(), ITEM_FOCUS);
                }
                else
                {
                    GuiEngine::GetInstance().UseStyle(view2.get(), ITEM);
                }
                //TODO:bug，funcSelected不能单纯相加
                createOne(view2.get(), i);
            }
        }
    }
    else
    {
        LOG_E("can't find item view\n");
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::StartDisplayHandleV2(Widget *window, int funcSelected, std::function<void(Widget *, int)> createOne, unsigned int maxItem)
{
    char name[16] = {0};
    // char params[64] = {0};
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(window, "itemView", true, view.get()))
    {
        LOG_I("find view, create the item %\n");
        for (unsigned int i = 0; i < 6; i++)
        {
            if (i >= maxItem)
            {
                break;
            }
            std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
            if (GuiEngine::GetInstance().ViewCreate(view.get(), 0, 0, 0, 0, view2.get()))
            {
                name[0] = 0;
                // params[0] = 0;
                sprintf(name, "item%d", funcSelected + i);
                GuiEngine::GetInstance().SetName(view2.get(), name);
                // sprintf(params, "default(x=0,y=%d,w=1194,h=200)", i * 202);
                // LOG_I("params = %s\n", params);
                GuiEngine::GetInstance().SetSelfLayout(view2.get(), "default(w=1769,h=113)");
                GuiEngine::GetInstance().SetChildrenLayout(view2.get(), "default(c=0,r=1)");
                if (i == 0)
                {
                    // 选中第一个
                    GuiEngine::GetInstance().UseStyle(view2.get(), ITEM_FOCUS);
                }
                else
                {
                    GuiEngine::GetInstance().UseStyle(view2.get(), ITEM);
                }
                //TODO:bug，funcSelected不能单纯相加
                createOne(view2.get(), i);
            }
        }
    }
    else
    {
        LOG_E("can't find item view\n");
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::RefreshItemHandle(void *ctx, void (*func)(void *))
{
    // IS_VALID_PTR(ctx)
    /**
     * @brief 
     * p 指针将在回调函数里面释放
     */
    Context *p = new Context;
    p->eventCallback = func;
    if (ctx)
    {
        KeyboardValue *p2 = new KeyboardValue;
        KeyboardValue key = KeyboardValue::KEYBOARD_VALUE_END;
        ((Context *)ctx)->GetData(key);
        *p2 = key;
        p->ctx = p2;
    }
    if (!GuiEngine::GetInstance().IdleQueue(p))
    {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::SwitchSelectedItem()
{
    if (!GetPrimaryPage())
    {
        LOG_E("something wrong happened.\n");
        return false;
    }
    return SwitchSelectedItemHandle(primaryWidget.get(), static_cast<int>(funcSelected), static_cast<int>(lastSelected));
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::RefreshItemIQ3(void *ctx)
{
    /**
     * @brief 
     * 如果当前item集合里面包含了切换的下一个item内容，直接切换即可
     * 否则先创建下一页item，再进行切换，翻页的效果
     */
    if (!SwitchSelectedItem())
    {
        IS_VALID_PTR(ctx)
        ContextV2<KeyboardValue> *pFunc = (ContextV2<KeyboardValue> *)ctx;
        // RefreshItemData data;
        // pFunc->GetDataV2(data);
        /**
         * @brief 
         * 如果没有找到下一个item，先创建下一页item
         */
        CreateItemsHandleV3(pFunc->RetrunData());
        SwitchSelectedItem();
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::CreateItemsHandleV3(KeyboardValue key)
{
    Context ctx;
    /**
     * @brief 
     * 设置项总数
     */
    unsigned int funcMax = static_cast<unsigned int>(FUNC::FUNCTION_END);
    FUNC create = lastSelected;
    KeyboardValue key2;
    if (!GetPrimaryPage())
    {
        LOG_E("can't create itme view.\n");
        return;
    }
    if (key == KeyboardValue::KEY_DIRECTION_LEFT || key == KeyboardValue::KEY_DIRECTION_UP)
    {
        key2 = KeyboardValue::KEY_DIRECTION_LEFT;
        /**
         * @brief 
         * 反向换页时，保证按升序排布，先降序
         */
        ctx.ctx = &key2;
        unsigned int total = ITEM_TOTAL;
        if (static_cast<unsigned int>(lastSelected) == 0)
        {
            /**
             * @brief 
             * 最后一页可能不满屏
             */
            total = funcMax % ITEM_TOTAL == 0 ? ITEM_TOTAL : funcMax % ITEM_TOTAL;
        }
        for (unsigned int i = 0; i <= total; i++)
        {
            CommonFunc::GetInstance().FunctionSelection(create, &ctx);
            if (static_cast<int>(create) == 0)
            {
                CommonFunc::GetInstance().FunctionSelection(create, &ctx);
                break;
            }
        }
    }
    /**
     * @brief 
     * 一次性销毁所有的item:destroy名称为"itemView"的view控件
     */
    std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().Lookup(primaryWidget.get(), "itemView", true, view.get()))
    {
        GuiEngine::GetInstance().Destroy(view.get());
    }
    /**
     * @brief 
     * 此处按升序创建每个设置项的item，布局方式由xml文件设置，多态管理不同的派生类要求。
     */
    std::unique_ptr<Widget> view2(GuiEngine::GetInstance().NewWidget());
    if (GuiEngine::GetInstance().ViewCreate(primaryWidget.get(), 0, 0, 0, 0, view2.get()))
    {
        SetItemView(view2.get());
        key2 = KeyboardValue::KEY_DIRECTION_RIGHT;
        ctx.ctx = &key2;
        CommonFunc::GetInstance().FunctionSelection(create, &ctx);
        for (unsigned int i = 0; i < ITEM_TOTAL; i++)
        {
            /**
             * @brief 
             * 虚拟功能是否存在，不使用虚拟功能时，忽略此判断
             */
            if (!TargetItemValid(static_cast<int>(create)))
            {
                break;
            }
            if (CreateItemView(static_cast<int>(create), view2.get()))
            {
                GuiEngine::GetInstance().UseStyle(view2.get(), ITEM);
                CreateOneItem(view2.get(), static_cast<int>(create));
                EnterItemHandle(static_cast<int>(create));
            }
            if (static_cast<unsigned int>(create) == funcMax - 1)
            {
                break;
            }
            CommonFunc::GetInstance().FunctionSelection(create, &ctx);
        }
    }
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
void SecondHandle<FUNC, PAGE, KEYEVENT>::Select(void *ctx)
{
    FUNC tmp = lastSelected;
    lastSelected = funcSelected;
    CommonFunc::GetInstance().FunctionSelection(funcSelected, ctx);
    /**
     * @brief 
     * 虚拟功能是否存在，不使用虚拟功能时，忽略此判断;
     * 设置项不存在，恢复到上一个状态，虚拟功能不支持循环选择；
     */
    if (!TargetItemValid(static_cast<int>(funcSelected)))
    {
        funcSelected = lastSelected;
        lastSelected = tmp;
        return;
    }
    if (!selectLoop)
    {
        /**
         * @brief 
         * 不允许循环切换
         */
        if (!(static_cast<int>(funcSelected) + 1 == static_cast<int>(lastSelected) || static_cast<int>(lastSelected) + 1 == static_cast<int>(funcSelected)))
        {
            funcSelected = lastSelected;
            return;
        }
    }
    RefreshItem(ctx);
    RefreshSlider();
    ItemEvent();
}
template <typename FUNC, typename PAGE, typename KEYEVENT>
bool SecondHandle<FUNC, PAGE, KEYEVENT>::KeyCmdResetHandle()
{
    typename std::map<FUNC, std::function<void()>>::iterator iter;
    iter = reset.find(funcSelected);
    if (iter != reset.end())
    {
        /**
         * @brief 
         * 调用设置项绑定的功能函数。
         */
        reset[funcSelected]();
        char name2[16] = {0};
        sprintf(name2, "item%d", static_cast<int>(funcSelected));
        std::unique_ptr<Widget> view6(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().Lookup(primaryWidget.get(), name2, true, view6.get()))
        {
            /**
             * @brief 
             * 把view控件设置为选中状态
             */
            if (SecondPageValid())
            {
                GetSecondPage().SetContrlView(view6.get());
                /**
                 * @brief Construct a new Item Selected object
                 * 设置项被选中处理，抽象流程，根据具体情况处理。
                 */
                GetSecondPage().ItemSelected();
            }
#if 0
            /**
             * @brief 
             * 设置设置项处于输入（当前设置）状态时的属性，如果选择状态即输入状态，可忽略该过程。
             * 这行代码属于架构性代码，不要轻易删掉。
             */
            GuiEngine::GetInstance().UseStyle(view6.get(), ITEM_SET);
#endif
            /**
             * @brief 
             * 通用设置，可在界面窗口属性重写属性实现不同的界面效果
             */
            SetSelectedItem(view6.get());
        }
        return true;
    }
    else
    {
        /**
         * @brief 
         * 只读的参数没有reset功能映射，无需做任何处理
         */
        LOG_E("something wrong happen, ignore if setting item is read-only\n");
        // ItemSelectedHandle();
        return false;
    }
}
#endif